import { injectable, inject } from 'inversify';
import { IUserService } from '../interfaces/IUserService';
import { User } from '../../domain/entities/user.entity';
import { IRepository } from '../../infrastructure/database/repositories/interfaces/IRepository';
import { TYPES } from '../../infrastructure/ioc/types';
import { LoggerService } from '../../infrastructure/logging/logger.service';

@injectable()
export class UserService implements IUserService {
  constructor(
    @inject(TYPES.UserRepository) private userRepository: IRepository<User>,
    @inject(TYPES.LoggerService) private logger: LoggerService
  ) {}

  async findById(id: string): Promise<User | null> {
    try {
      return await this.userRepository.findById(id);
    } catch (error: any) {
      this.logger.error(`Error finding user by ID: ${error.message}`);
      return null;
    }
  }

  async findByUsername(username: string): Promise<User | null> {
    try {
      return await this.userRepository.findOne({ where: { username } });
    } catch (error: any) {
      this.logger.error(`Error finding user by username: ${error.message}`);
      return null;
    }
  }

  async findByEmail(email: string): Promise<User | null> {
    try {
      return await this.userRepository.findOne({ where: { email } });
    } catch (error: any) {
      this.logger.error(`Error finding user by email: ${error.message}`);
      return null;
    }
  }

  async updateUser(id: string, userData: Partial<User>): Promise<User> {
    try {
      const user = await this.userRepository.findById(id);
      if (!user) {
        throw new Error(`User with ID ${id} not found`);
      }
      
      // Merge user data
      Object.assign(user, userData);
      
      return await this.userRepository.save(user);
    } catch (error: any) {
      this.logger.error(`Error updating user: ${error.message}`);
      throw error;
    }
  }

  async setUserStatus(id: string, status: string): Promise<User> {
    return this.updateUser(id, { status });
  }

  async assignRole(id: string, role: string): Promise<User> {
    return this.updateUser(id, { role });
  }

  async grantPermissions(id: string, permissions: string[]): Promise<User> {
    try {
      const user = await this.userRepository.findById(id);
      if (!user) {
        throw new Error(`User with ID ${id} not found`);
      }
      
      // Add new permissions without duplicates
      const uniquePermissions = Array.from(new Set([...user.permissions, ...permissions]));
      user.permissions = uniquePermissions;
      
      return await this.userRepository.save(user);
    } catch (error: any) {
      this.logger.error(`Error granting permissions: ${error.message}`);
      throw error;
    }
  }

  async revokePermissions(id: string, permissions: string[]): Promise<User> {
    try {
      const user = await this.userRepository.findById(id);
      if (!user) {
        throw new Error(`User with ID ${id} not found`);
      }
      
      // Remove specified permissions
      user.permissions = user.permissions.filter(p => !permissions.includes(p));
      
      return await this.userRepository.save(user);
    } catch (error: any) {
      this.logger.error(`Error revoking permissions: ${error.message}`);
      throw error;
    }
  }

  async deleteUser(id: string): Promise<boolean> {
    try {
      const user = await this.userRepository.findById(id);
      if (!user) {
        return false;
      }
      
      await this.userRepository.delete(id);
      return true;
    } catch (error: any) {
      this.logger.error(`Error deleting user: ${error.message}`);
      return false;
    }
  }
} 